package com.nulldev.util.data.Arrays.maps;

import java.util.Map;

import com.nulldev.util.data.Arrays.maps.trie.TrieMap;
import com.nulldev.util.internal.backport.concurrency9.Maps;
import com.nulldev.util.manage.experiments.Experiments;

public class FastMaps {

	private static final boolean USE_TRIE_MAPS = Experiments.get("nullUtil://use-trie-maps/").isActive();

	public static <K, V> Map<K, V> map() {
		if (USE_TRIE_MAPS)
			return new TrieMap<K, V>();
		else
			return new FastHashMap<K, V>(true);
	}

	public static <K, V> Map<K, V> map(final Map<K, V> map) {
		if (USE_TRIE_MAPS)
			return new TrieMap<K, V>(map);
		else
			return new FastHashMap<K, V>(map, true);
	}

	public static <K> Map<K, K> map(final int size, final K[][] map) {
		if (size < 0)
			throw new IllegalArgumentException("size < 0!");
		final Map<K, K> m = map(size + map.length);
		for (final K[] k : map) {
			if (k.length == 2) {
				m.put(k[0], k[1]);
			}
		}
		return m;
	}

	public static <K> Map<K, K> map(final K[][] map) {
		final Map<K, K> m = map(map.length);
		for (final K[] k : map) {
			if (k.length == 2) {
				m.put(k[0], k[1]);
			}
		}
		return m;
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> uniMap(final Object[][] map) {
		final Map<K, V> m = map(map.length);
		for (final Object[] k : map) {
			if (k.length == 2) {
				m.put((K) k[0], (V) k[1]);
			}
		}
		return m;
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> fixedUniMap(final Object[][] map) {
		final Map<K, V> m = map(map.length);
		for (final Object[] k : map) {
			if (k.length == 2) {
				m.put((K) k[0], (V) k[1]);
			}
		}
		return Maps.copyOf(m);
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> uniMap(final int extraSize, final Object[][] map) {
		if (extraSize < 0)
			throw new IllegalArgumentException("extraSize < 0!");
		final Map<K, V> m = map(extraSize + map.length);
		for (final Object[] k : map) {
			if (k.length == 2) {
				m.put((K) k[0], (V) k[1]);
			}
		}
		return m;
	}

	public static <K, V> Map<K, V> map(final int size) {
		if (USE_TRIE_MAPS)
			return new TrieMap<K, V>();
		else
			return new FastHashMap<K, V>(size, true);
	}
}
